package nio;

import org.apache.commons.io.IOUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.SelectionKey;
import java.nio.channels.Selector;
import java.nio.channels.SocketChannel;
import java.util.Iterator;
import java.util.Set;

/**
 * Created by GanJc on 2015/11/15.
 */
public class TimeClient {

    private static final Logger logger = LoggerFactory.getLogger(TimeClient.class);

    public static void main(String[] args) {
        int port = 8888;
        new Thread(new TimeClientHandle("127.0.0.1",port),"time-client-001").start();
    }

    private static class TimeClientHandle implements Runnable{

        private String ip ;

        private int port ;

        private Selector selector ;

        private SocketChannel socketChannel ;

        private volatile boolean stop ;

        public TimeClientHandle(String ip ,int port) {
            this.ip = ip ==null?"127.0.0.1":ip;
            this.port = port ;
            try {
                selector = Selector.open();
                socketChannel = SocketChannel.open();
                socketChannel.configureBlocking(false);
            } catch (IOException e) {
                e.printStackTrace();
                System.exit(1);
            }
        }

        @Override
        public void run() {
            try{
                doConnect();
            }catch (Exception e){
                e.printStackTrace();
                System.exit(1);
            }

            while (!stop){
                try{
                    selector.select(1000);
                    Set<SelectionKey> selectionKeys = selector.selectedKeys();
                    Iterator<SelectionKey> it = selectionKeys.iterator();
                    while (it.hasNext()){
                        SelectionKey key = it.next();
                        it.remove();
                        try{
                            handleInputKey(key);
                        }catch (Exception e){
                            e.printStackTrace();
                            key.cancel();
                            if (key.channel()!=null){
                                key.channel().close();
                            }
                        }
                    }
                }catch (Exception e){
                    e.printStackTrace();
                    System.exit(1);
                }
            }
            IOUtils.closeQuietly(selector);
        }

        private void handleInputKey(SelectionKey key) throws IOException {
            if(key.isValid()){
                SocketChannel  sc = (SocketChannel) key.channel();
                if(key.isConnectable()){
                    if(sc.finishConnect()){
                        sc.register(selector,SelectionKey.OP_READ);
                        doWrite(sc);
                    }else {
                        System.exit(1);//连接失败 进程退出
                    }
                }
                if(key.isReadable()){
                    ByteBuffer readBuffer = ByteBuffer.allocate(1024);
                    int read = sc.read(readBuffer);
                    if(read>0){
                        readBuffer.flip();
                        byte [] bytes = new byte[readBuffer.remaining()];
                        readBuffer.get(bytes);
                        String body = new String(bytes,"utf-8");
                        logger.info("now is : {}",body);
                        this.stop = true;
                    }else if(read<0){
                        key.cancel();
                        sc.close();
                    }else {
                        ; //读到0字节 忽略
                    }
                }
            }
        }

        private void doWrite(SocketChannel sc) throws IOException {
            byte[] req = "TIME".getBytes();
            ByteBuffer writeBuffer = ByteBuffer.allocate(1024);
            writeBuffer.put(req);
            writeBuffer.flip();
            sc.write(writeBuffer);
            if(!writeBuffer.hasRemaining()){
                logger.info("send order success!");
            }
        }

        private void doConnect() throws IOException {
            //如果连接成功， 字节注册到多路复用器上 发送请求消息 读取应答消息
            if(socketChannel.connect(new InetSocketAddress(ip,port))){
                socketChannel.register(selector,SelectionKey.OP_READ);
                doWrite(socketChannel);
            }else {
                socketChannel.register(selector,SelectionKey.OP_CONNECT);
            }
        }

    }
}
